import pandas as pd
from typing import Dict

from interfaces.data_loader import IDataLoader
from interfaces.form_metadata import IFormMetadataProvider
from interfaces.transformers import IBaseSubjects, IJoiner, IPivotMetrics, IFailureList, ICycleProcessor, IBloodDraw, ILbup
from interfaces.excel_writer import IExcelWriter
from constants import (
    SUBJECT_NUMBER, BASE_COLS, MERGE_KEYS, DATA_FESTIVAL, LINE_NUMBER, FormAllConstants, BLOOD_DRAW
)


class DataProcessingService:
    def __init__(
        self,
        data_loader: IDataLoader,
        metadata: IFormMetadataProvider,
        base_subjects: IBaseSubjects,
        joiner: IJoiner,
        pivot: IPivotMetrics,
        failure: IFailureList,
        cycles: ICycleProcessor,
        writer: IExcelWriter,
        blood_draw: IBloodDraw,
        lbup: ILbup,
        default_source_data: str,
    ):
        self.data_loader = data_loader
        self.metadata = metadata
        self.base_subjects = base_subjects
        self.joiner = joiner
        self.pivot = pivot
        self.failure = failure
        self.cycles = cycles
        self.writer = writer
        self.blood_draw = blood_draw
        self.lbup = lbup
        self.default_source_data = default_source_data

    def _build_key_indicator_config(self, sheet_name: str, outgroup_section: str, screening_section: str) -> Dict:
        return {
            'sheet_name': sheet_name,
            'base_cols': BASE_COLS,
            'period_cols': MERGE_KEYS,
            'period_conditions': {
                'screening': lambda df: (df[DATA_FESTIVAL] == screening_section),
                'outgroup': lambda df: (df[DATA_FESTIVAL] == outgroup_section),
            },
            'merge_keys': MERGE_KEYS,
        }

    def run(self) -> str:
        all_results: Dict[str, pd.DataFrame] = {}

        qualified = self.base_subjects.get_qualified_subjects()
        all_results["入组成功受试者"] = qualified

        failure_list = self.failure.get_failure_list()
        all_results["失败受试者列表"] = failure_list

        merged = self.joiner.join_tables_by_subject(
            base_df=qualified,
            input_excel_path=self.default_source_data,
            join_key=SUBJECT_NUMBER,
            skip_missing_key=True,
        )
        for sheet_name, df in merged.items():
            all_results[sheet_name] = df

        lab_oids = self.metadata.get_targets((FormAllConstants.IsLab, True), FormAllConstants.ModuleOID, True)
        outgroup_section = self.metadata.get_targets((FormAllConstants.IsOutGroup, True), FormAllConstants.FolderName, True)[0]
        screening_section = self.metadata.get_targets((FormAllConstants.IsBaseline, True), FormAllConstants.FolderName, True)[0]

        lab_results = {}
        for oid in lab_oids:
            cfg = self._build_key_indicator_config(oid, outgroup_section, screening_section)
            df = self.pivot.verify_key_metrics(cfg)
            lab_results[oid + "关键指标"] = df
        if lab_results:
            combined_lab = pd.concat(lab_results.values(), axis=0, ignore_index=True, join='outer').fillna("")
            all_results["实验室关键指标"] = combined_lab

        outgroup_oids = self.metadata.get_targets((FormAllConstants.IsOutGroup, True), FormAllConstants.ModuleOID, True)
        for oid in outgroup_oids:
            cfg = self._build_key_indicator_config(oid, outgroup_section, screening_section)
            df = self.pivot.verify_key_metrics(cfg)
            all_results[oid + "关键指标"] = df

        # 处理 IsLbup（独立实现）
        self.lbup.process_lbup(all_results)

        # 处理血样采集（IsBloodDraw）
        self.blood_draw.process_blood_draw(all_results)

        visit_cycles = self.metadata.get_targets((FormAllConstants.IsVisitCycle, True), FormAllConstants.FolderName, True)
        visit_sources = self.metadata.get_targets((FormAllConstants.IsVisitCycle, True), FormAllConstants.ModuleOID, True)
        self.cycles.process_cycles(all_results, visit_cycles, visit_sources)

        output_path = self.writer.save_and_format_excel(all_results)
        return output_path